﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.IO;
using System.Net;
using System.Threading;
using System.Text.RegularExpressions;

namespace PowerPointWebController
{
    class Listener
    {
        private HttpListener httpListener = null;
        private IPAddress lockedIp = null;
        private bool keepListening = true;

        public int listenPort = 0;

        public delegate void RaiseIPAddressNotify_delegate(IPAddress ip);
        public event RaiseIPAddressNotify_delegate IPAddressNotify;

        public void start(int port)
        {
            listenPort = port;
            if (!HttpListener.IsSupported)
            {
                throw new ApplicationException("Listener is not supported. Listener only supported in XP SP2 or higher.");
            }

            httpListener = new HttpListener();

            //Get the ip address of the user's machine and add them as prefixes
            //This makes them available to the http listener.
            IPAddress[] addresses = Dns.GetHostAddresses(Dns.GetHostName());

            foreach (IPAddress a in addresses)
            {
                string prefix = String.Format("http://{0}:{1}/", a.ToString(), listenPort);

                httpListener.Prefixes.Add(prefix);
                if (IPAddressNotify != null)
                    IPAddressNotify(a);
            }

            //Add local prefix as well...
            httpListener.Prefixes.Add(String.Format("http://127.0.0.1:{0}/",listenPort));

            //Start the http listener
            httpListener.Start();

            //Start our listener thread.
            Thread listenerThread = new Thread(new ParameterizedThreadStart(listen));
            listenerThread.Start();
        }

        public void stop()
        {
            if (httpListener != null)
            {
                httpListener.Stop();
                httpListener.Close();
            }
            keepListening = false;
        }

        private static void respond(HttpListenerResponse response, string html)
        {
            try
            {
                if (response != null && response.OutputStream != null && response.OutputStream.CanWrite)
                {
                    byte[] buffer = System.Text.Encoding.UTF8.GetBytes(html);
                    response.ContentLength64 = buffer.Length;
                    response.OutputStream.Write(buffer, 0, buffer.Length);
                    response.OutputStream.Flush();
                    response.OutputStream.Close();
                }
            }
            catch
            {
            }
            finally
            {
                if (response != null)
                    response.Close();
            }
        }

        private void listen(object state)
        {
            while (keepListening)
            {
                if (httpListener != null)
                {
                    HttpListenerContext context = null;
                    try
                    {
                        context = httpListener.GetContext();
                    }
                    catch 
                    {
                        return;
                    }

                    HttpListenerRequest request = context.Request;
                    HttpListenerResponse response = context.Response;

                    //Going to lock down the listener to a single ip address
                    //That is, the ip address of the first client that makes a request.
                    if (lockedIp == null)
                        lockedIp = request.RemoteEndPoint.Address;

                    string command = Regex.Replace(request.Url.PathAndQuery, @"/(.*)$", "$1");
                    string responstText = "<ok/>";

                    if(!lockedIp.Equals(request.RemoteEndPoint.Address))
                    {
                        //Then the client is not the same as the first
                        //client that connected.  Abort.
                        response.StatusCode = 404;
                        response.Abort();
                    }
                    else if (CommandHandler.handle(command, ref responstText))
                    {
                        //Display the html that comes back
                        //from the CommandHandler handle call
                        respond(response, responstText);
                    }
                    else
                    {
                        response.ContentType = "text/html";
                        response.StatusCode = 200;

                        //Uses the page resource for displaying our 
                        //main page.
                        responstText = pages.page;

                        //Respond with the returned page html.
                        respond(response, responstText);
                    }
                }
            }
        }
    }
}
